<?php

// [ 微信支付 ]
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1  下单
// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3  签名

namespace app\wechat\lib;
use think\Config;
use think\Request;
use app\common\lib\Order;

class Pay
{
    // 支付签名
    public static function sign($prepayId)
    {
        $arr = [
            'appId'     => Config::get('appid'),
            'timeStamp' => time(),
            'nonceStr'  => mkstr(16),
            'package'   => 'prepay_id=' . $prepayId,
            'signType'  => 'MD5',
        ];

        // 字典序排序
        ksort($arr);

        // 生成 URL-encode 之后的请求字符串
        $str = '';
        foreach ($arr as $key => $val) {
            $str .= '&' . $key . '=' . $val;
        }
        $str = substr($str,1);

        // echo $str;
        // echo '<br />';

        // 拼接key
        $str .= '&key=' . Config::get('key');

        // echo $str;
        // echo '<br />';

        // sha1加密
        $signature = md5($str);

        // 转大写
        $signature = strtoupper($signature);

        // echo $signature;
        // echo '<br />';

        $arr['paySign'] = $signature;

        return $arr;
    }

    // 统一下单
    // https://api.mch.weixin.qq.com/pay/unifiedorder
    // @param  projectId  项目ID
    //         payMark    支付标识,cp-初评付款,cx-诚信保证金
    //         title      商品名称,eg:项目评估费
    //         openid     Openid
    //         money      最终支付金额
    //         notifyUrl  微信支付结果通知的回调地址
    //         tradeType  支付类型, JSAPI-公众号支付 NATIVE-扫码支付
    //         code       优惠码,可选
    /* @return
                appid:"wx473f54dc14979325"
                mch_id:"1487031512"
                nonce_str:"rN1QxWgTargy3hay"
                prepay_id:"wx20170819195952db50098aa80056632199"
                result_code:"SUCCESS"
                return_code:"SUCCESS"
                return_msg:"OK"
                sign:"DC0E11D915745144AF72717113482CA0"
                trade_type:"JSAPI"
    */
    public static function order($projectId, $payMark, $title, $openId, $money, $notifyUrl, $tradeType = 'JSAPI', $code = '')
    {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $arr = [
            'appid'            => Config::get('appid'),                    // 公众账号ID
            'attach'           => $title,                                  // 附加数据，在查询API和支付通知中原样返回，可作为自定义参数使用
            'mch_id'           => Config::get('mch_id'),                   // 商户号
            'nonce_str'        => mkstr(32,0),                             // 随机字符串,长度要求在32位以内
            'body'             => '价值链-' . $title,                      // 商品描述,规范:商家名称-销售商品类目
            'detail'           => '{"title":'. $title . ',"openid":'. $openId . ',"money":'. $money . '}',
                                                                           // 商品详情,JsonArray
            'out_trade_no'     => date('YmdHis') . rand(100000,999999),    // 商户系统内部订单号，要求32个字符内，同一个商户号下唯一
            'total_fee'        => $money * 100,                            // 订单总金额，单位为分
            'spbill_create_ip' => Request::instance()->ip(),               // APP和网页支付提交用户端ip，Native支付填调用微信支付API的机器IP
            'notify_url'       => $notifyUrl,                              // 异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数
            'trade_type'       => $tradeType,                              // 交易类型,取值如下：JSAPI，NATIVE，APP
            'product_id'       => $projectId,                              // 商品ID,trade_type=NATIVE时（即扫码支付），此参数必传。此参数为二维码中包含的商品ID，商户自行定义
            'openid'           => $openId,                                 // trade_type=JSAPI时（即公众号支付），此参数必传，此参数为微信用户在商户对应appid下的唯一标识
            // 'sign'             => '',                                   // 签名,通过签名算法计算得出的签名值
        ];

        // openid为空时,去掉,不参与签名
        if ( empty($arr['openid']) ) unset($arr['openid']);

        // 字典序排序
        ksort($arr);

        // 签名
        $arr['sign'] = self::_signature($arr);

        // 转xml
        $xml  = '<xml>';
        foreach ($arr as $key => $val) {
            $xml .= '<' . $key . '>' . $val . '</' . $key . '>';
        }
        $xml .= '</xml>';
        
        // p($xml);

        $res  = https_curl($url,'POST',$xml);

        // p($res);die;
        
        $res = xml_to_array($res);

        // p($res);die;
        
        // 写入订单表
        $data = [
            'product_id'   => $projectId,
            'pay_mark'     => $payMark,
            'openid'       => $openId,
            'money'        => $arr['total_fee'],
            'body'         => $title,
            'trade_type'   => $tradeType,
            'code'         => $code,
            'out_trade_no' => $arr['out_trade_no'],
        ];
        Order::set($data);
        
        return $res;
    }

    /* 签名
    第一步，设所有发送或者接收到的数据为集合M，将集合M内非空参数值的参数按照参数名ASCII码从小到大排序（字典序），
            使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA。
            特别注意以下重要规则：
            ◆ 参数名ASCII码从小到大排序（字典序）；
            ◆ 如果参数的值为空不参与签名；
            ◆ 参数名区分大小写；
            ◆ 验证调用返回或微信主动通知签名时，传送的sign参数不参与签名，将生成的签名与该sign值作校验。
            ◆ 微信接口可能增加字段，验证签名时必须支持增加的扩展字段
    第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，
            得到sign值signValue。
            ◆ key设置路径：微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
    */
    private static function _signature($arr)
    {
        // 用URL键值对的格式拼接成字符串
        // $stringA  = http_build_query($arr);
        // 生成 URL-encode 之后的请求字符串
        $str = '';
        foreach ($arr as $key => $val) {
            $str .= '&' . $key . '=' . $val;
        }
        $stringA = substr($str,1);

        // p($stringA);

        // 拼接商户平台key
        $stringA .= '&key=' . Config::get('key');

        // p($stringA);

        // md5加密
        $stringSignTemp = md5($stringA);

        // 转大写
        $signValue = strtoupper($stringSignTemp);

        return $signValue;
    }
}